<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>src/lib/testers.coffee</title>
    <link rel="stylesheet" href="http://yui.yahooapis.com/3.9.1/build/cssgrids/cssgrids-min.css">
    <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css">
    <link rel="stylesheet" href="../assets/css/main.css" id="site_styles">
    <link rel="icon" href="../assets/favicon.ico">
    <script src="http://yui.yahooapis.com/combo?3.9.1/build/yui/yui-min.js"></script>
</head>
<body class="yui3-skin-sam">

<div id="doc">
    <div id="hd" class="yui3-g header">
        <div class="yui3-u-3-4">
                <h1><img src="../assets/css/logo.png" title="" width="117" height="52"></h1>
        </div>
        <div class="yui3-u-1-4 version">
            <em>API Docs for: </em>
        </div>
    </div>
    <div id="bd" class="yui3-g">

        <div class="yui3-u-1-4">
            <div id="docs-sidebar" class="sidebar apidocs">
                <div id="api-list">
                    <h2 class="off-left">APIs</h2>
                    <div id="api-tabview" class="tabview">
                        <ul class="tabs">
                            <li><a href="#api-classes">Classes</a></li>
                            <li><a href="#api-modules">Modules</a></li>
                        </ul>
                
                        <div id="api-tabview-filter">
                            <input type="search" id="api-filter" placeholder="Type to filter APIs">
                        </div>
                
                        <div id="api-tabview-panel">
                            <ul id="api-classes" class="apis classes">
                                <li><a href="../classes/BasePlugin.html">BasePlugin</a></li>
                                <li><a href="../classes/Collection.html">Collection</a></li>
                                <li><a href="../classes/Docpad.html">Docpad</a></li>
                                <li><a href="../classes/docpadUtil.html">docpadUtil</a></li>
                                <li><a href="../classes/DocumentModel.html">DocumentModel</a></li>
                                <li><a href="../classes/ElementsCollection.html">ElementsCollection</a></li>
                                <li><a href="../classes/Events.html">Events</a></li>
                                <li><a href="../classes/FileModel.html">FileModel</a></li>
                                <li><a href="../classes/FilesCollection.html">FilesCollection</a></li>
                                <li><a href="../classes/MetaCollection.html">MetaCollection</a></li>
                                <li><a href="../classes/Model.html">Model</a></li>
                                <li><a href="../classes/PluginLoader.html">PluginLoader</a></li>
                                <li><a href="../classes/PluginTester.html">PluginTester</a></li>
                                <li><a href="../classes/QueryCollection.html">QueryCollection</a></li>
                                <li><a href="../classes/ScriptCollection.html">ScriptCollection</a></li>
                                <li><a href="../classes/ServerTester.html">ServerTester</a></li>
                                <li><a href="../classes/StylesCollection.html">StylesCollection</a></li>
                            </ul>
                
                
                            <ul id="api-modules" class="apis modules">
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="yui3-u-3-4">
                <div id="api-options">
                    Show:
                    <label for="api-show-inherited">
                        <input type="checkbox" id="api-show-inherited" checked>
                        Inherited
                    </label>
            
                    <label for="api-show-protected">
                        <input type="checkbox" id="api-show-protected">
                        Protected
                    </label>
            
                    <label for="api-show-private">
                        <input type="checkbox" id="api-show-private">
                        Private
                    </label>
                    <label for="api-show-deprecated">
                        <input type="checkbox" id="api-show-deprecated">
                        Deprecated
                    </label>
            
                </div>
            
            <div class="apidocs">
                <div id="docs-main">
                    <div class="content">
<h1 class="file-heading">File: src/lib/testers.coffee</h1>

<div class="file">
    <pre class="code prettyprint linenums">
# =====================================
# Requires

# Standard Library
pathUtil = require(&#x27;path&#x27;)

# External
safefs = require(&#x27;safefs&#x27;)
balUtil = require(&#x27;bal-util&#x27;)
extendr = require(&#x27;extendr&#x27;)
joe = require(&#x27;joe&#x27;)
assert = require(&#x27;assert&#x27;)
{equal, deepEqual, errorEqual} = require(&#x27;assert-helpers&#x27;)
CSON = require(&#x27;cson&#x27;)
{difference} = require(&#x27;underscore&#x27;)

# Local
DocPad = require(&#x27;./docpad&#x27;)
docpadUtil = require(&#x27;./util&#x27;)


# =====================================
# Helpers

# Prepare
# We want the plugn port to be a semi-random number above 2000
pluginPort = 2000 + parseInt(String(Date.now()).substr(-6, 4))
testers = {
	CSON,
	DocPad
}


# ---------------------------------
# Classes

###*
# The Plugin Tester class
# @class PluginTester
# @constructor
###
testers.PluginTester =
class PluginTester
	# Add support for BasePlugin.extend(proto)
	@extend: require(&#x27;csextends&#x27;)


	###*
	# Default plugin config
	# @property {Object}
	###
	config:
		testerName: null
		pluginName: null
		pluginPath: null
		testPath: null
		outExpectedPath: null
		removeWhitespace: false
		contentRemoveRegex: null
		autoExit: &#x27;safe&#x27;

	###*
	# Default DocPad config
	# @property {Object}
	###
	docpadConfig:
		global: true
		port: null
		logLevel: (if (&#x27;-d&#x27; in process.argv) then 7 else 5)
		rootPath: null
		outPath: null
		srcPath: null
		pluginPaths: null
		enableUnlistedPlugins: true
		enabledPlugins: null
		skipUnsupportedPlugins: false
		catchExceptions: false
		environment: null


	###*
	# The DocPad instance
	# @private
	# @property {Object}
	###
	docpad: null
	
	###*
	# Constructor method
	# @method constructor
	# @param {Object} [config={}]
	# @param {Object} [docpadConfig={}]
	# @param {Function} next
	###
	constructor: (config={},docpadConfig={},next) -&gt;
		# Apply Configuration
		tester = @
		@config = extendr.deepExtendPlainObjects({}, PluginTester::config, @config, config)
		@docpadConfig = extendr.deepExtendPlainObjects({}, PluginTester::docpadConfig, @docpadConfig, docpadConfig)
		@docpadConfig.port ?= ++pluginPort
		@config.testerName ?= &quot;#{@config.pluginName} plugin&quot;

		# Extend Configuration
		@config.testPath or= pathUtil.join(@config.pluginPath, &#x27;test&#x27;)
		@config.outExpectedPath or= pathUtil.join(@config.testPath, &#x27;out-expected&#x27;)

		# Extend DocPad Configuration
		@docpadConfig.rootPath or= @config.testPath
		@docpadConfig.outPath or= pathUtil.join(@docpadConfig.rootPath, &#x27;out&#x27;)
		@docpadConfig.srcPath or= pathUtil.join(@docpadConfig.rootPath, &#x27;src&#x27;)
		@docpadConfig.pluginPaths ?= [@config.pluginPath]
		defaultEnabledPlugins = {}
		defaultEnabledPlugins[@config.pluginName] = true
		@docpadConfig.enabledPlugins or= defaultEnabledPlugins

		# Test API
		joe.describe @config.testerName, (suite,task) -&gt;
			tester.describe = tester.suite = suite
			tester.it = tester.test = task
			tester.done = tester.exit = (next) -&gt;
				tester.docpad?.action(&#x27;destroy&#x27;, next)
			next?(null, tester)

		# Chain
		@


	###*
	# Get tester Configuration
	# @method getConfig
	# @return {Object}
	###
	getConfig: -&gt;
		return @config

	###*
	# Get the plugin instance
	# @method getPlugin
	# @return {Object} the plugin
	###
	getPlugin: -&gt;
		return @docpad.getPlugin(@getConfig().pluginName)


	###*
	# Create the DocPad instance
	# @method testCreate
	###
	testCreate: =&gt;
		# Prepare
		tester = @
		docpadConfig = @docpadConfig

		# Create Instance
		@test &quot;create&quot;, (done) -&gt;
			new DocPad docpadConfig, (err, docpad) -&gt;
				return done(err)  if err
				tester.docpad = docpad

				# init docpad in case the plugin is starting from scratch
				tester.docpad.action &#x27;init&#x27;, (err) -&gt;
					if err and err.message isnt tester.docpad.getLocale().skeletonExists
						return done(err)  # care about the error providing it isn&#x27;t the skeleton exists error

					# clean up the docpad out directory
					tester.docpad.action &#x27;clean&#x27;, (err) -&gt;
						return done(err)  if err

						# install anything on the website that needs to be installed
						tester.docpad.action(&#x27;install&#x27;, done)

		# Chain
		@

	###*
	# Test Loaded
	# @method
	###
	testLoad: =&gt;
		# Prepare
		tester = @

		# Test
		@test &quot;load plugin #{tester.config.pluginName}&quot;, (done) -&gt;
			tester.docpad.loadedPlugin tester.config.pluginName, (err,loaded) -&gt;
				return done(err)  if err
				assert.ok(loaded)
				return done()

		# Chain
		@

	# Perform Server
	testServer: (next) =&gt;
		# Prepare
		tester = @

		# Handle
		@test &quot;server&quot;, (done) -&gt;
			tester.docpad.action &#x27;server&#x27;, (err) -&gt;
				return done(err)

		# Chain
		@

	###*
	# Test generate
	# @method
	###
	testGenerate: =&gt;
		# Prepare
		tester = @

		# Test
		@test &quot;generate&quot;, (done) -&gt;
			tester.docpad.action &#x27;generate&#x27;, (err) -&gt;
				return done(err)

		# Chain
		@

	###*
	# Test everything
	# @method {Object}
	###
	testEverything: =&gt;
		# Prepare
		tester = @

		# Tests
		@testCreate()
		@testLoad()
		@testGenerate()
		@testServer()
		@testCustom?()

		# Finish
		@finish()

		# Chain
		@

	###*
	# Finish
	# @method finish
	###
	finish: -&gt;
		# Prepare
		tester = @

		# Finish
		if tester.config.autoExit
			@test &#x27;finish up&#x27;, (next) -&gt;
				tester.exit(next)

		# Chain
		@

###*
# Server tester
# @class ServerTester
# @extends PluginTester
# @constructor
###
testers.ServerTester =
class ServerTester extends PluginTester


###*
# Rednderer tester
# @class ServerTester
# @extends PluginTester
# @constructor
###
testers.RendererTester =
class RendererTester extends PluginTester
	# Test Generation
	testGenerate: -&gt;
		# Prepare
		tester = @

		# Test
		@suite &quot;generate&quot;, (suite,test) -&gt;
			test &#x27;action&#x27;, (done) -&gt;
				tester.docpad.action &#x27;generate&#x27;, (err) -&gt;
					return done(err)

			suite &#x27;results&#x27;, (suite,test,done) -&gt;
				# Get actual results
				balUtil.scanlist tester.docpadConfig.outPath, (err,outResults) -&gt;
					return done(err)  if err

					# Get expected results
					balUtil.scanlist tester.config.outExpectedPath, (err,outExpectedResults) -&gt;
						return done(err)  if err

						# Prepare
						outResultsKeys = Object.keys(outResults)
						outExpectedResultsKeys = Object.keys(outExpectedResults)

						# Check we have the same files
						test &#x27;same files&#x27;, -&gt;
							outDifferenceKeys = difference(outExpectedResultsKeys, outResultsKeys)
							deepEqual(outDifferenceKeys, [], &#x27;The following file(s) should have been generated&#x27;)
							outDifferenceKeys = difference(outResultsKeys, outExpectedResultsKeys)
							deepEqual(outDifferenceKeys, [], &#x27;The following file(s) should not have been generated&#x27;)

						# Check the contents of those files match
						outResultsKeys.forEach (key) -&gt;
							test &quot;same file content for: #{key}&quot;, -&gt;
								# Fetch file value
								actual = outResults[key]
								expected = outExpectedResults[key]

								# Remove empty lines
								if tester.config.removeWhitespace is true
									replaceLinesRegex = /\s+/g
									actual = actual.replace(replaceLinesRegex, &#x27;&#x27;)
									expected = expected.replace(replaceLinesRegex, &#x27;&#x27;)

								# Content regex
								if tester.config.contentRemoveRegex
									actual = actual.replace(tester.config.contentRemoveRegex, &#x27;&#x27;)
									expected = expected.replace(tester.config.contentRemoveRegex, &#x27;&#x27;)

								# Compare
								equal(actual, expected)

						# Forward
						done()

		# Chain
		@

###*
# Test a plugin
# test({pluginPath: String})
# @property test
###
testers.test =
test = (testerConfig, docpadConfig) -&gt;
	# Configure
	testerConfig.testerClass ?= PluginTester
	testerConfig.pluginPath = pathUtil.resolve(testerConfig.pluginPath)
	testerConfig.pluginName ?= pathUtil.basename(testerConfig.pluginPath).replace(&#x27;docpad-plugin-&#x27;,&#x27;&#x27;)
	testerConfig.testerPath ?= pathUtil.join(&#x27;out&#x27;, &quot;#{testerConfig.pluginName}.tester.js&quot;)
	testerConfig.testerPath = pathUtil.resolve(testerConfig.pluginPath, testerConfig.testerPath)  if testerConfig.testerPath

	# Create tester
	complete = -&gt;
		# Accept string inputs for testerClass
		testerConfig.testerClass = testers[testerConfig.testerClass]  if typeof testerConfig.testerClass is &#x27;string&#x27;

		# Create our tester
		new testerConfig.testerClass testerConfig, docpadConfig, (err,testerInstance) -&gt;
			throw err  if err

			# Run the tests
			testerInstance.testEverything()

	# Load the tester file
	if testerConfig.testerPath
		safefs.exists testerConfig.testerPath, (exists) -&gt;
			testerConfig.testerClass = require(testerConfig.testerPath)(testers)  if exists
			complete()

	# User the default tester
	else
		complete()

	# Chain
	return testers


# ---------------------------------
# Export Testers
module.exports = testers

    </pre>
</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="../assets/vendor/prettify/prettify-min.js"></script>
<script>prettyPrint();</script>
<script src="../assets/js/yui-prettify.js"></script>
<script src="../assets/../api.js"></script>
<script src="../assets/js/api-filter.js"></script>
<script src="../assets/js/api-list.js"></script>
<script src="../assets/js/api-search.js"></script>
<script src="../assets/js/apidocs.js"></script>
</body>
</html>
